﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IndignadoFramework.BackBone.Model;
using IndignadoFramework.DataAccessLayer.EntityModels;
using IndignadoFramework.BackBone.DTO;

namespace IndignadoFramework.BackBone.InternalServices.Implementacion
{
    public class ContenidoUsuarioServicesImpl : ContenidoUsuarioServices
    {
        public void addContenidoImagenUsuario(ImagenModel contenido)
        {
            Imagen contenidoEntity = new Imagen();

            AutoMapper.Mapper.CreateMap<ImagenModel, Imagen>();
            contenidoEntity = AutoMapper.Mapper.Map(contenido, contenidoEntity);

            using (IndignadoFrameworkEntities context = new IndignadoFrameworkEntities())
            {
                context.AddObject("Contenidos", contenidoEntity);
                context.SaveChanges();
            }
        }

        public void addContenidoVideoUsuario(VideoModel contenido)
        {
            Video contenidoEntity = new Video();

            AutoMapper.Mapper.CreateMap<VideoModel, Video>();
            contenidoEntity = AutoMapper.Mapper.Map(contenido, contenidoEntity);

            using (IndignadoFrameworkEntities context = new IndignadoFrameworkEntities())
            {
                context.AddObject("Contenidos", contenidoEntity);
                context.SaveChanges();
            }
        }

        public void addContenidoLinkUsuario(LinkModel contenido)
        {
            Link contenidoEntity = new Link();

            AutoMapper.Mapper.CreateMap<LinkModel, Link>();
            contenidoEntity = AutoMapper.Mapper.Map(contenido, contenidoEntity);

            using (IndignadoFrameworkEntities context = new IndignadoFrameworkEntities())
            {
                context.AddObject("Contenidos", contenidoEntity);
                context.SaveChanges();
            }
        }

        public IEnumerable<ContenidoModelDTO> getContenidosByDate(int movimientoId, int? pagina)
        {
            List<ContenidoModelDTO> listaContenidos = new List<ContenidoModelDTO>();
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos where cont.MovimientoId == movimientoId
                                                        && cont.ContenidoDadoBaja == false select cont;

            // Ordeno el resultado por fecha
            IEnumerable<Contenido> contenidos = contenidosEntity.ToList().OrderByDescending(contenidoEntity => contenidoEntity.ContenidoFechaCreacion);
            // Obtengo la constante M del Movimiento
            int M = 0;

            if (contenidos.Any())
                M = contenidos.First().Movimiento.MovimientoConstM;            

            foreach (Contenido contenidoEntity in contenidos)
            {
                if (contenidoEntity.GetType().ToString().Contains("Imagen"))
                {
                    ImagenModelDTO contenidoModel = new ImagenModelDTO();
                    AutoMapper.Mapper.CreateMap<Imagen, ImagenModelDTO>();
                    contenidoModel = AutoMapper.Mapper.Map(((Imagen)contenidoEntity), contenidoModel);
                    contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                    contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                    contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                    listaContenidos.Add(contenidoModel);
                }
                else
                {
                    if (contenidoEntity.GetType().ToString().Contains("Video"))
                    {
                        VideoModelDTO contenidoModel = new VideoModelDTO();
                        AutoMapper.Mapper.CreateMap<Video, VideoModelDTO>();
                        contenidoModel = AutoMapper.Mapper.Map(((Video)contenidoEntity), contenidoModel);
                        contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                        contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                        contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                        listaContenidos.Add(contenidoModel);
                    }
                    else
                    {
                        LinkModelDTO contenidoModel = new LinkModelDTO();
                        AutoMapper.Mapper.CreateMap<Link, LinkModelDTO>();
                        contenidoModel = AutoMapper.Mapper.Map(((Link)contenidoEntity), contenidoModel);
                        contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                        contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                        contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                        listaContenidos.Add(contenidoModel);
                    }
                }
            }

            // Verifico si el parametro tiene un valor
            if (pagina.HasValue)
            {
                return listaContenidos.Skip(pagina.Value * M).Take(M);
            }
            else
            {
                return listaContenidos.Take(M);
            }

        }

        public IEnumerable<ContenidoModelDTO> getContenidosByRanking(int movimientoId, int? pagina)
        {
            List<ContenidoModelDTO> listaContenidos = new List<ContenidoModelDTO>();
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos where cont.MovimientoId == movimientoId 
                                                        && cont.ContenidoDadoBaja == false select cont;

            // Ordeno el resultado por fecha
            IEnumerable<Contenido> contenidos = contenidosEntity.ToList().OrderByDescending(contenidoEntity => contenidoEntity.ContenidoFechaCreacion);
            // Obtengo la constante N del Movimiento
            int N = 0;

            if (contenidos.Any())
                N = contenidos.First().Movimiento.MovimientoConstN;

            foreach (Contenido contenidoEntity in contenidos)
            {
                if (contenidoEntity.GetType().ToString().Contains("Imagen"))
                {
                    ImagenModelDTO contenidoModel = new ImagenModelDTO();
                    AutoMapper.Mapper.CreateMap<Imagen, ImagenModelDTO>();
                    contenidoModel = AutoMapper.Mapper.Map(((Imagen)contenidoEntity), contenidoModel);
                    contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                    contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                    contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                    listaContenidos.Add(contenidoModel);
                }
                else
                {
                    if (contenidoEntity.GetType().ToString().Contains("Video"))
                    {
                        VideoModelDTO contenidoModel = new VideoModelDTO();
                        AutoMapper.Mapper.CreateMap<Video, VideoModelDTO>();
                        contenidoModel = AutoMapper.Mapper.Map(((Video)contenidoEntity), contenidoModel);
                        contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                        contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                        contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                        listaContenidos.Add(contenidoModel);
                    }
                    else
                    {
                        LinkModelDTO contenidoModel = new LinkModelDTO();
                        AutoMapper.Mapper.CreateMap<Link, LinkModelDTO>();
                        contenidoModel = AutoMapper.Mapper.Map(((Link)contenidoEntity), contenidoModel);
                        contenidoModel.UsuarioNombre = contenidoEntity.Usuario.UsuarioNombre;
                        contenidoModel.CantMeGusta = countMeGusta(contenidoEntity);
                        contenidoModel.CantInadecuado = countInadecuado(contenidoEntity);
                        listaContenidos.Add(contenidoModel);
                    }
                }
            }

            // Verifico si el parametro tiene un valor
            if (pagina.HasValue)
            {
                return listaContenidos.OrderByDescending(mg => mg.CantMeGusta).Skip(pagina.Value * N).Take(N);
            }
            else
            {
                return listaContenidos.OrderByDescending(mg => mg.CantMeGusta).Take(N);
            }
        }

        public bool existPaginaSiguienteByDate(int movimientoId, int? pagina)
        {
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            int M = context.Movimientos.First(m => m.Id == movimientoId).MovimientoConstM;
            IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos
                                                     where cont.MovimientoId == movimientoId
                                                        && cont.ContenidoDadoBaja == false
                                                     select cont;

            // Ordeno el resultado por fecha
            IEnumerable<Contenido> contenidos = contenidosEntity.ToList().OrderByDescending(contenidoEntity => contenidoEntity.ContenidoFechaCreacion);
            // Verifico si el parametro tiene un valor
            if (pagina.HasValue)
            {
                return contenidos.Skip((pagina.Value + 1) * M).Take(M).Count() > 0;
            }
            else
            {
                return contenidos.Skip(M).Take(M).Count() > 0;
            }
        }

        public bool existPaginaSiguienteByRanking(int movimientoId, int? pagina)
        {
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            int N = context.Movimientos.First(m => m.Id == movimientoId).MovimientoConstN;
            IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos
                                                     where cont.MovimientoId == movimientoId
                                                         && cont.ContenidoDadoBaja == false
                                                     select cont;

            // Ordeno el resultado por fecha
            IEnumerable<Contenido> contenidos = contenidosEntity.ToList().OrderByDescending(contenidoEntity => contenidoEntity.ContenidoFechaCreacion);
            // Verifico si el parametro tiene un valor
            if (pagina.HasValue)
            {
                return contenidos.Skip((pagina.Value + 1) * N).Take(N).Count() > 0;
            }
            else
            {
                return contenidos.Skip(N).Take(N).Count() > 0;
            }
        }

        public IEnumerable<ContenidoModelDTO> getContenidosInadecuados(Boolean inadecuadosBajar)
        {
            List<ContenidoModelDTO> listaContenidos = new List<ContenidoModelDTO>();
            MovimientoServicesImpl movs = new MovimientoServicesImpl();
            List<MovementModel> movimientos = movs.getMovimientos();
            foreach (MovementModel movimiento in movimientos)
            {
                // Obtengo la variable X del movimiento
                // Si quiero los contenidos inadecuados para darlos de baja, obtengo el valor de X
                // De lo contrario, en X se pone 1, para que encuentre todos los contenidos con marcas de inadecuado
                int X;
                if (inadecuadosBajar)
                {
                    X = movimiento.MovimientoConstX;
                }
                else X = 1;
                // Obtengo el ID del movimiento para utilizar en la consulta
                int idMov = movimiento.Id;
                // Obtengo una lista de contenidos (aún no dados de baja) del movimiento para chequear los inadecuados
                IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
                IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos where cont.MovimientoId == idMov 
                                                             && cont.ContenidoDadoBaja == false select cont;
                foreach (Contenido contenido in contenidosEntity)
                {
                    int cantidadInadecuado = countInadecuado(contenido);
                    // Contenido inadecuado detected
                    if (cantidadInadecuado >= X)
                    {
                        if (contenido.GetType().ToString().Contains("Imagen"))
                        {
                            ImagenModelDTO contenidoModel = new ImagenModelDTO();
                            AutoMapper.Mapper.CreateMap<Imagen, ImagenModelDTO>();
                            contenidoModel = AutoMapper.Mapper.Map(((Imagen)contenido), contenidoModel);
                            contenidoModel.UsuarioNombre = contenido.Usuario.UsuarioNombre;
                            contenidoModel.CantMeGusta = countMeGusta(contenido);
                            contenidoModel.CantInadecuado = countInadecuado(contenido);
                            listaContenidos.Add(contenidoModel);
                        }
                        else
                        {
                            if (contenido.GetType().ToString().Contains("Video"))
                            {
                                VideoModelDTO contenidoModel = new VideoModelDTO();
                                AutoMapper.Mapper.CreateMap<Video, VideoModelDTO>();
                                contenidoModel = AutoMapper.Mapper.Map(((Video)contenido), contenidoModel);
                                contenidoModel.UsuarioNombre = contenido.Usuario.UsuarioNombre;
                                contenidoModel.CantMeGusta = countMeGusta(contenido);
                                contenidoModel.CantInadecuado = countInadecuado(contenido);
                                listaContenidos.Add(contenidoModel);
                            }
                            else
                            {
                                LinkModelDTO contenidoModel = new LinkModelDTO();
                                AutoMapper.Mapper.CreateMap<Link, LinkModelDTO>();
                                contenidoModel = AutoMapper.Mapper.Map(((Link)contenido), contenidoModel);
                                contenidoModel.UsuarioNombre = contenido.Usuario.UsuarioNombre;
                                contenidoModel.CantMeGusta = countMeGusta(contenido);
                                contenidoModel.CantInadecuado = countInadecuado(contenido);
                                listaContenidos.Add(contenidoModel);
                            }
                        }
                    }
                }
            }
            return listaContenidos.OrderByDescending(dl => dl.CantInadecuado);
        }

        public void deleteContenidos(IEnumerable<ContenidoModelDTO> eliminar)
        {
            List<int> ids = new List<int>();
            foreach (ContenidoModelDTO contenido in eliminar)
            {
                ids.Add(contenido.Id);
            }
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            IQueryable<Contenido> contenidosEntity = from cont in context.Contenidos where ids.Contains(cont.Id)
                                                            && cont.ContenidoDadoBaja == false select cont;
            foreach (Contenido contenido in contenidosEntity)
            {
                contenido.ContenidoDadoBaja = true;
            }
            context.SaveChanges();
        }

        public IEnumerable<UsuarioModelDTO> updateUsuarios(Boolean eliminar)
        {
            List<UsuarioModelDTO> listaUsuarios = new List<UsuarioModelDTO>();
            // Recorro los movimientos para obtener la variable Z
            MovimientoServicesImpl movs = new MovimientoServicesImpl();
            List<MovementModel> movimientos = movs.getMovimientos();
            foreach (MovementModel movimiento in movimientos)
            {
                // Obtengo la variable Z del movimiento
                int Z = movimiento.MovimientoConstZ;
                // Obtengo el ID del movimiento para utilizar en la consulta
                int idMov = movimiento.Id;
                // Obtengo una lista de usuarios no dados de baja del movimiento
                IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
                IQueryable<Usuario> usuariosEntity = from usu in context.Usuarios where usu.MovimientoId == idMov 
                                                         && usu.UsuarioDadoBaja == false select usu;
                foreach (Usuario usuario in usuariosEntity)
                {
                    //Obtengo una lista de contenidos inadecuados para el par usuario - movimiento
                    IndignadoFrameworkEntities contextContenidos = new IndignadoFrameworkEntities();
                    IQueryable<Contenido> contenidoEntity = from cont in contextContenidos.Contenidos 
                                                            where cont.MovimientoId == idMov 
                                                               && cont.UsuarioId == usuario.Id 
                                                               && cont.ContenidoDadoBaja == true select cont;
                    int inadecuadosUsuario = contenidoEntity.Count();
                    // Si la cantidad de contenidos inadecuados del usuario es mayor que Z, actualizo su tupla
                    if (inadecuadosUsuario >= Z)
                    {
                        usuario.UsuarioDadoBaja = true;
                        //mapeo
                        UsuarioModelDTO usuarioModel = new UsuarioModelDTO();
                        AutoMapper.Mapper.CreateMap<Usuario, UsuarioModelDTO>();
                        usuarioModel = AutoMapper.Mapper.Map(usuario, usuarioModel);
                        usuarioModel.Id = usuario.Id;
                        usuarioModel.MovimientoId = usuario.MovimientoId;
                        usuarioModel.UsuarioDadoBaja = usuario.UsuarioDadoBaja;
                        usuarioModel.UsuarioFacebook = usuario.UsuarioFacebook;
                        usuarioModel.UsuarioFechaRegistro = usuario.UsuarioFechaRegistro;
                        usuarioModel.UsuarioLogueado = usuario.UsuarioLogueado;
                        usuarioModel.UsuarioMail = usuario.UsuarioMail;
                        usuarioModel.UsuarioNombre = usuario.UsuarioNombre;
                        usuarioModel.UsuarioRedSocial = usuario.UsuarioRedSocial;
                        usuarioModel.UsuarioTwitter = usuario.UsuarioTwitter;
                        usuarioModel.UsuarioUbicacionX = usuario.UsuarioUbicacionX;
                        usuarioModel.UsuarioUbicacionY = usuario.UsuarioUbicacionY;                        
                        listaUsuarios.Add(usuarioModel);
                    }
                }
                if (eliminar)
                {
                    context.SaveChanges();
                }
            }
            return listaUsuarios;
        }

        // Cuenta la cantidad de Me Gusta de un Contenido
        int countMeGusta(Contenido cont)
        {
            int count = 0;
            DateTime now = DateTime.Now;
            foreach (Marca m in cont.Marca)
            {
                if (m.GetType().Name.Contains("MeGusta"))
                {
                    // Solo lo sumo si el Me Gusta se hizo en el ultimo mes
                    if (((MeGusta)m).MeGustaFecha.AddMonths(1) >= now)
                        count++;
                }
            }
            return count;
        }

        // Cuenta la cantidad de Inadecuado de un Contenido
        int countInadecuado(Contenido cont)
        {
            int count = 0;
            foreach (Marca m in cont.Marca)
            {
                if (m.GetType().Name.Contains("Inadecuado"))
                {
                    count++;
                }
            }
            return count;
        }

        public int tagMeGusta(MarcaModel marca)
        {
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            IQueryable<Marca> marcasEntity = from m in context.Marcas
                                                     where m.MovimientoId == marca.MovimientoId
                                                         && m.ContenidoId == marca.ContenidoId
                                                         && m.UsuarioId == marca.UsuarioId
                                                     select m;
            if (marcasEntity.Any())
            {
                // Dejo esto por si en algun momento se hace algo mas
            }
            else
            {
                MeGusta marcaEntity = new MeGusta();

                AutoMapper.Mapper.CreateMap<MarcaModel, MeGusta>();
                marcaEntity = AutoMapper.Mapper.Map(marca, marcaEntity);
                marcaEntity.MeGustaFecha = DateTime.Now;
                context.AddObject("Marcas", marcaEntity);
                context.SaveChanges();
            }
            return countMeGusta(context.Contenidos.First(c => c.Id == marca.ContenidoId && c.MovimientoId == marca.MovimientoId));
            
        }

        public int tagInadecuado(MarcaModel marca)
        {
            IndignadoFrameworkEntities context = new IndignadoFrameworkEntities();
            IQueryable<Marca> marcasEntity = from m in context.Marcas
                                             where m.MovimientoId == marca.MovimientoId
                                                 && m.ContenidoId == marca.ContenidoId
                                                 && m.UsuarioId == marca.UsuarioId
                                             select m;
            if (marcasEntity.Any())
            {
                // Dejo esto por si en algun momento se hace algo mas
            }
            else
            {
                Inadecuado marcaEntity = new Inadecuado();

                AutoMapper.Mapper.CreateMap<MarcaModel, Inadecuado>();
                marcaEntity = AutoMapper.Mapper.Map(marca, marcaEntity);
                context.AddObject("Marcas", marcaEntity);
                context.SaveChanges();
                deleteContenidos (getContenidosInadecuados(true));
                IEnumerable<UsuarioModelDTO> usuarios = updateUsuarios(true);
            }
            return countInadecuado(context.Contenidos.First(c => c.Id == marca.ContenidoId && c.MovimientoId == marca.MovimientoId));
        }
    }
}
